// cell.c // Eric Rollins // 4 dimensional cellular automata (only 3 currently used) // // Modified to display async cellular automata read from file. // // gcc cell.c -lGLEW -lGL -lGLU -lglut -lm -O3 #include #include #include #include #define ROWS 52 #define COLS 52 #define LVLS 52 #define WVLS 1 typedef struct _color { float r; float g; float b; } color; void resetMatrixMode(); #define STEP_SIZE 1 // position and orientation of eye static GLdouble eyex = 0.0; static GLdouble eyey = 0.0; static GLdouble eyez = 50.0; static GLdouble centerx = 0.0; static GLdouble centery = 0.0; static GLdouble centerz = 0.0; static GLdouble upx = 0.0; static GLdouble upy = 1.0; static GLdouble upz = 0.0; #define WINDOW_WIDTH 512 #define WINDOW_HEIGHT 512 GLfloat light_position0[] = { 0.0, 0.0, 100.0, 1.0}; #define PI 3.14159265359 static double heading = PI; // 0 == looking down +z; // pi/2 == looking down +x static double lookAngle = 0.0; // 0 == looking in x-z plane; // pi/2 == looking up +y // clamped to +- pi/2 // now optional command line params double TURN_STEP = 0.1; // radians (5.73 degrees) double MOVE_STEP = 4.0; static int displayW = WVLS/2; color cs[ROWS][COLS][LVLS][WVLS]; color csNext[ROWS][COLS][LVLS][WVLS]; //--------------------------------------------------------------------------- #define CENTER (ROWS/2) void initCellStatus(){ int r,c,l,w; for(r = 0; r < ROWS; r++){ for(c = 0; c < COLS; c++){ for(l = 0; l < LVLS; l++){ for(w = 0; w < WVLS; w++){ cs[r][c][l][w].r = 0.0; cs[r][c][l][w].g = 0.0; cs[r][c][l][w].b = 0.0; } } } } } //--------------------------------------------------------------------------- static FILE *datafile = 0; void nextCellStatus(){ int x,y,z; float r,g,b; int items = fscanf(datafile,"%d,%d,%d:%f,%f,%f",&x,&y,&z,&r,&g,&b); int w; if(items < 6){ fprintf(stderr,"scanned < 6 items\n"); return; } if(x >= COLS || y >= ROWS || z >= LVLS){ fprintf(stderr,"%d %d %d out of bounds\n", x, y, z); return; } for(w = 0; w < WVLS; w++){ cs[y][x][z][w].r = r; cs[y][x][z][w].g = g; cs[y][x][z][w].b = b; } } //--------------------------------------------------------------------------- void printErrors() { GLenum errCode; const GLubyte *errString; if((errCode = glGetError()) != GL_NO_ERROR){ errString = gluErrorString(errCode); fprintf(stderr, "OpenGL Error: %s\n", errString); } } //--------------------------------------------------------------------------- #define THRESHOLD 0.3 void drawCubeAt(float x, float y, float z, float red, float green, float blue) { if((red < THRESHOLD) && (green < THRESHOLD) && (blue < THRESHOLD)) return; if(red > 1.0) red = 1.0; if(green > 1.0) green = 1.0; if(blue > 1.0) blue = 1.0; if(red < 0.0) red = 0.0; if(green < 0.0) green = 0.0; if(blue < 0.0) blue = 0.0; // GLfloat mat[] = { red, green, blue}; glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); glEnable(GL_COLOR_MATERIAL); float opacity = (red + green + blue) / 3.0; if( opacity > 1.0) opacity = 1.0; glColor4f(red, green, blue, opacity); glBegin(GL_QUADS); // A glNormal3f(0.0f, 0.0f, 1.0f); // glTexCoord2f(0.0, 0.0); glVertex3f(x-1.0f, y-1.0f, z+1.0f); // glTexCoord2f(1.0, 0.0); glVertex3f(x+1.0f, y-1.0f, z+1.0f); // glTexCoord2f(1.0, 1.0); glVertex3f(x+1.0f, y+1.0f, z+1.0f); // glTexCoord2f(0.0, 1.0); glVertex3f(x-1.0f, y+1.0f, z+1.0f); // B glNormal3f(1.0f, 0.0f, 0.0f); // glTexCoord2f(0.0, 0.0); glVertex3f(x+1.0f, y-1.0f, z+1.0f); // glTexCoord2f(1.0, 0.0); glVertex3f(x+1.0f, y-1.0f, z-1.0f); // glTexCoord2f(1.0, 1.0); glVertex3f(x+1.0f, y+1.0f, z-1.0f); // glTexCoord2f(0.0, 1.0); glVertex3f(x+1.0f, y+1.0f, z+1.0f); // C glNormal3f(0.0f, 0.0f, -1.0f); // glTexCoord2f(0.0, 0.0); glVertex3f(x+1.0f, y-1.0f, z-1.0f); // glTexCoord2f(1.0, 0.0); glVertex3f(x-1.0f, y-1.0f, z-1.0f); // glTexCoord2f(1.0, 1.0); glVertex3f(x-1.0f, y+1.0f, z-1.0f); // glTexCoord2f(0.0, 1.0); glVertex3f(x+1.0f, y+1.0f, z-1.0f); // D glNormal3f(-1.0f, 0.0f, 0.0f); // glTexCoord2f(0.0, 0.0); glVertex3f(x-1.0f,y-1.0f, z-1.0f); // glTexCoord2f(1.0, 0.0); glVertex3f(x-1.0f, y-1.0f, z+1.0f); // glTexCoord2f(1.0, 1.0); glVertex3f(x-1.0f, y+1.0f, z+1.0f); // glTexCoord2f(0.0, 1.0); glVertex3f(x-1.0f, y+1.0f, z-1.0f); // E glNormal3f(0.0f, -1.0f, 0.0f); // glTexCoord2f(0.0, 0.0); glVertex3f(x-1.0f, y-1.0f, z-1.0f); // glTexCoord2f(1.0, 0.0); glVertex3f(x+1.0f, y-1.0f, z-1.0f); // glTexCoord2f(1.0, 1.0); glVertex3f(x+1.0f, y-1.0f, z+1.0f); // glTexCoord2f(0.0, 1.0); glVertex3f(x-1.0f, y-1.0f, z+1.0f); // F glNormal3f(0.0f, 1.0f, 0.0f); // glTexCoord2f(0.0, 0.0); glVertex3f(x-1.0f, y+1.0f, z+1.0f); // glTexCoord2f(1.0, 0.0); glVertex3f(x+1.0f, y+1.0f, z+1.0f); // glTexCoord2f(1.0, 1.0); glVertex3f(x+1.0f, y+1.0f, z-1.0f); // glTexCoord2f(0.0, 1.0); glVertex3f(x-1.0f, y+1.0f, z-1.0f); glEnd(); glDisable(GL_COLOR_MATERIAL); } //--------------------------------------------------------------------------- void redraw(void) { int r,c,l; #ifdef DISPLAY_2D return; #endif glLoadIdentity(); gluLookAt(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz); glLightfv(GL_LIGHT0, GL_POSITION, light_position0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); for(r = 0; r < ROWS; r++){ for(c = 0; c < COLS; c++){ for(l = 0; l < LVLS; l++){ // if((r == 0) && (c == 0)&&(l == 0)){ //fprintf(stderr,"%f\n", cs[r][c][l][displayW].r); //} drawCubeAt(0.0f + (c - (COLS/2))*2.5, 0.0f + (r - (ROWS/2))*2.5, 0.0f + (l - (LVLS/2))*2.5, cs[r][c][l][displayW].r, cs[r][c][l][displayW].g, cs[r][c][l][displayW].b); } } } glutSwapBuffers(); printErrors(); } //--------------------------------------------------------------------------- static int run = 0; static long count = 0; void updateScene(void) { if(run){ int s; #ifdef USE_GPGPU gpgpuNextInit(); #endif for(s = 0; s < STEP_SIZE; s++){ #ifdef USE_GPGPU gpgpuNextStep(); #else nextCellStatus(); #endif } #ifdef USE_GPGPU gpgpuNextEnd(); #endif fprintf(stderr,"finished next %ld (STEP_SIZE = %d)\n", count++, STEP_SIZE); } glutPostRedisplay(); } //--------------------------------------------------------------------------- // returns true if a collision has occurred (or edge crossed, in case of // wall-less region) // will also set falling to true if an appropriate edge is crossed int collideWall(int forward) { return 0; } //--------------------------------------------------------------------------- void keyboardFunc(unsigned char key, int x, int y) { //fprintf(stderr,"key = %c (%d)\n", key, key); if((key == 'k') || (key == 'K')) { //fprintf(stderr,"forward\n"); eyez += MOVE_STEP*cos(heading); eyex += MOVE_STEP*sin(heading); if(collideWall(1)) { eyez -= MOVE_STEP*cos(heading); eyex -= MOVE_STEP*sin(heading); } } else if((key == 'j') || (key == 'J')) { //fprintf(stderr,"backward\n"); eyez -= MOVE_STEP*cos(heading); eyex -= MOVE_STEP*sin(heading); if(collideWall(0)) { eyez += MOVE_STEP*cos(heading); eyex += MOVE_STEP*sin(heading); } }else if((key == 'h') || (key == 'H')){ //fprintf(stderr,"left\n"); heading += TURN_STEP; } else if((key == 'l') || (key == 'L')) { //fprintf(stderr,"right\n"); heading -= TURN_STEP; } else if ((key == 'n') || (key == 'N')){ #ifdef USE_GPGPU gpgpuNextInit(); gpgpuNextStep(); gpgpuNextEnd(); #else nextCellStatus(); #endif fprintf(stderr,"finished next\n"); } else if ((key == 'r') || (key == 'R')){ if(run) run = 0; else run = 1; } else if ((key == 'q') || (key == 'Q')){ exit(0); } else if ((key == 'w') || (key == 'W')){ displayW++; if(displayW > (WVLS-1)) displayW = 0; fprintf(stderr,"W = %d\n",displayW); } centerz = 10000*cos(heading); centerx = 10000*sin(heading); //fprintf(stderr,"ex = %f ey = %f ez = %f cx = %f cy = %f cz = %f\n", // eyex, eyey, eyez, centerx, centery, centerz); } //--------------------------------------------------------------------------- static int lastx = -1; static int lasty = -1; void mouseFunc(int button, int state, int x, int y) { if (state == GLUT_DOWN) { lastx = x; lasty = y; } else { lastx = -1; lasty = -1; } } //--------------------------------------------------------------------------- void motionFunc(int x, int y) { int dx = x - lastx; int dy = y - lasty; if((lastx == -1) || (lasty == -1)) { // fprintf(stderr,"motionFunc called without mouseFunc\n"); return; } if(dx) { if(dx < 0) { heading += TURN_STEP; } else { heading -= TURN_STEP; } centerz = 10000*cos(heading); centerx = 10000*sin(heading); } if(dy) { if(dy < 0) { lookAngle += TURN_STEP; } else { lookAngle -= TURN_STEP; } if(lookAngle > PI/2) lookAngle = PI/2; else if(lookAngle < -PI/2) lookAngle = -PI/2; centery = 10000*sin(lookAngle); } lastx = x; lasty = y; } //--------------------------------------------------------------------------- int main(int argc, char **argv){ if(argc < 2){ fprintf(stderr, "input filename required\n"); exit(1); } fprintf(stderr,"turn step = %6.2f degrees\n", (TURN_STEP * 360) / (2.0 * PI)); fprintf(stderr,"move_step = %6.2f\n", MOVE_STEP); fprintf(stderr,"\n"); fprintf(stderr,"h == turn left\n"); fprintf(stderr,"l == turn right\n"); fprintf(stderr,"k == move forward\n"); fprintf(stderr,"j == move backward\n"); fprintf(stderr,"mouse == turn left,\n"); fprintf(stderr," turn right,\n"); fprintf(stderr," look down,\n"); fprintf(stderr," look up\n"); fprintf(stderr,"r == toggle run\n"); fprintf(stderr,"n == next (single step)\n"); fprintf(stderr,"w == increment W dimension\n"); fprintf(stderr,"q == QUIT\n"); if(!(datafile = fopen(argv[1],"r"))) { fprintf(stderr,"fopen %s failed\n", argv[1]); exit(1); } initCellStatus(); glutInit(&argc, argv); glutInitWindowSize(WINDOW_WIDTH,WINDOW_HEIGHT); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutCreateWindow("Cell"); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glEnable(GL_NORMALIZE); glShadeModel(GL_SMOOTH); // need to reset posion after each eye move! glLightfv(GL_LIGHT0, GL_POSITION, light_position0); glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); resetMatrixMode(); glutIdleFunc(updateScene); glutDisplayFunc(redraw); glutKeyboardFunc(keyboardFunc); glutMouseFunc(mouseFunc); glutMotionFunc(motionFunc); #ifdef USE_GPGPU gpgpuInit(); #endif glutMainLoop(); } void resetMatrixMode(){ #ifdef DISPLAY_2D return; #endif glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1.0, 1.0, -1.0, 1.0, 1.5, 2000000.0); glMatrixMode(GL_MODELVIEW); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); // enable transparency glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_DEPTH_TEST); }